﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using CloudShot.Controls;
using CloudShot.Core.Interfaces;
using CloudShot.Entities;
using CloudShot.Logic;
using CloudShot.Properties;
using CloudShot.Settings;

namespace CloudShot.Forms
{
  internal partial class SettingsForm : Form
  {
    private readonly StorageContainer _storageContainer;
    private readonly IConfigurationSection _appConfiguration;
    private readonly List<IImageStorage> _storages;
    private IImageStorage _activeStorage;

    public SettingsForm(StorageContainer storageContainer, IConfigurationSection appConfiguration)
    {
      _storageContainer = storageContainer;
      _appConfiguration = appConfiguration;
      _storages = storageContainer.Storages.ToList();

      InitializeComponent();
      Icon = Resources.applicationIcon;

      LoadGeneralSettings();
      LoadStoragesSettings();
      cboStorages.SelectedItem = _storageContainer.ActiveStorage;
    }

    public void ActivateHotkeysTab()
    {
      tabContainer.SelectTab(tabHotkeys);
    }

    private void LoadStoragesSettings()
    {
      pnlSettings.Controls.Clear();

      foreach (ISettingsControl settingsUIHolder in GetSettingsUIHolders())
      {
        settingsUIHolder.Loading();
        settingsUIHolder.Control.Dock = DockStyle.Fill;
        settingsUIHolder.Control.Visible = false;
        pnlSettings.Controls.Add(settingsUIHolder.Control);
      }

      cboStorages.DisplayMember = "Name";
      cboStorages.DataSource = _storages;
    }

    private void LoadGeneralSettings()
    {
      var appSettings = _appConfiguration.GetOrCreateAs<CloudShotSettings>();

      chkOpenInBrowser.Checked = appSettings.IsOpenInBrowser;
      hkbShot.Hotkey = appSettings.ShotHotkey;
      hkbInstantShot.Hotkey = appSettings.InstantShotHotkey;
      hkbRecord.Hotkey = appSettings.RecordHotkey;
      chkNotifications.Checked = appSettings.IsShowNotifications;
      chkStartWithWindows.Checked = appSettings.IsStartWithComputer;
      chkEnableSounds.Checked = appSettings.IsSoundsEnabled;
      chkScreenshotsCaptureMouse.Checked = appSettings.IsCaptureMouseInScreenshots;

      hkbFollowMouse.Hotkey = appSettings.FollowMouseHotkey;
      hkbStartPauseRecording.Hotkey = appSettings.StartPauseRecordingHotkey;
      hkbFinishRecording.Hotkey = appSettings.FinishRecordingHotkey;

      var shotTypes = new List<KeyValuePair<string, ShotType>>
      {
        new KeyValuePair<string, ShotType>(Resources.SettingsForm_DefaultShotAction_ShotAndEdit, ShotType.ShotAndEdit),
        new KeyValuePair<string, ShotType>(Resources.SettingsForm_DefaultShotAction_InstantShot, ShotType.InstantShot),
        new KeyValuePair<string, ShotType>(Resources.SettingsForm_DefaultShotAction_Record, ShotType.Record),
      };

      cboDefaultShotAction.DataSource = shotTypes;
      cboDefaultShotAction.DisplayMember = "Key";
      cboDefaultShotAction.ValueMember = "Value";

      KeyValuePair<string, ShotType> selectedItem = shotTypes.FirstOrDefault(x => x.Value == appSettings.SystemTrayClick);
      cboDefaultShotAction.SelectedItem = selectedItem;

      chkShowHints.Checked = !appSettings.IsHintsDisabled;

#if DEBUG
      chkStartWithWindows.Enabled = false;
      chkStartWithWindows.Text += " (Turned off in DEBUG)";
#endif
    }

    private void ShowActiveStorageSettings()
    {
      if (_activeStorage == null)
        return;
      
      lblDescription.Text = _activeStorage.Description;
      
      foreach (ISettingsControl settingsUIHolder in GetSettingsUIHolders())
      {
        settingsUIHolder.Control.Visible = settingsUIHolder == _activeStorage.SettingsControl;
      }
    }

    private void SaveSettings()
    {
      var appSettings = _appConfiguration.GetOrCreateAs<CloudShotSettings>();

      appSettings.IsOpenInBrowser = chkOpenInBrowser.Checked;
      appSettings.ShotHotkey = hkbShot.Hotkey;
      appSettings.InstantShotHotkey = hkbInstantShot.Hotkey;
      appSettings.RecordHotkey = hkbRecord.Hotkey;
      appSettings.IsShowNotifications = chkNotifications.Checked;
      appSettings.IsSoundsEnabled = chkEnableSounds.Checked;
      appSettings.IsStartWithComputer = chkStartWithWindows.Checked;
      appSettings.IsCaptureMouseInScreenshots = chkScreenshotsCaptureMouse.Checked;
      appSettings.SystemTrayClick = cboDefaultShotAction.SelectedItem is KeyValuePair<string, ShotType>
        ? ((KeyValuePair<string, ShotType>)cboDefaultShotAction.SelectedItem).Value
        : ShotType.ShotAndEdit;
      appSettings.IsHintsDisabled = !chkShowHints.Checked;

      appSettings.FollowMouseHotkey = hkbFollowMouse.Hotkey;
      appSettings.StartPauseRecordingHotkey = hkbStartPauseRecording.Hotkey;
      appSettings.FinishRecordingHotkey = hkbFinishRecording.Hotkey;

      ApplyStorageSettings();

      if (_activeStorage != null)
        appSettings.ActiveStorageName = _activeStorage.Name;

      _appConfiguration.SaveAs(appSettings);
    }

    private void ApplyStorageSettings()
    {
      foreach (IImageStorage storage in _storages)
      {
        ISettingsControl control = storage.SettingsControl;

        if (control != null)
          control.OkClicked();
      }
    }

    private IEnumerable<ISettingsControl> GetSettingsUIHolders()
    {
      return _storages.Where(x => x.SettingsControl != null).Select(x => x.SettingsControl);
    }

    private bool ValidateSettings()
    {
      if (_activeStorage == null)
      {
        MessageBox.Show(Resources.SettingsForm_NoActiveStorageError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
        tabContainer.SelectTab(tabStorage);
        cboStorages.Focus();
        return false;
      }

      foreach (ISettingsControl holder in GetSettingsUIHolders())
      {
        if (!holder.ValidateData())
        {
          tabContainer.SelectTab(tabStorage);
          cboStorages.SelectedItem = holder.Storage;
          return false;
        }
      }

      if (!ValidateHotkeys())
      {
        MessageBox.Show(Resources.SettingsForm_HasDuplicateHotkeys, Application.ProductName,
                        MessageBoxButtons.OK, MessageBoxIcon.Error);

        tabContainer.SelectTab(tabHotkeys);
        return false;
      }

      return true;
    }

    private bool ValidateHotkeys()
    {
      var hotkeys = new List<HotkeyBox>();

      if (!hkbShot.Hotkey.IsEmpty)
        hotkeys.Add(hkbShot);

      if (!hkbInstantShot.Hotkey.IsEmpty)
        hotkeys.Add(hkbInstantShot);

      if (!hkbRecord.Hotkey.IsEmpty)
        hotkeys.Add(hkbRecord);

      if (!hkbFollowMouse.Hotkey.IsEmpty)
        hotkeys.Add(hkbFollowMouse);
      
      if (!hkbStartPauseRecording.Hotkey.IsEmpty)
        hotkeys.Add(hkbStartPauseRecording);
      
      if (!hkbFinishRecording.Hotkey.IsEmpty)
        hotkeys.Add(hkbFinishRecording);

      IEnumerable<IGrouping<Hotkey, HotkeyBox>> hkGroups = hotkeys.GroupBy(hk => hk.Hotkey);

      if (hkGroups.Any(group => group.Count() > 1)) //has the same hotkeys
        return false;

      return true;
    }

    #region Event Handlers

    private void OnOkClick(object sender, EventArgs e)
    {
      if (!ValidateSettings())
        return;

      SaveSettings();

      _storageContainer.ActiveStorage = _activeStorage;

      DialogResult = DialogResult.OK;
    }

    private void OnActiveStorageChanged(object sender, EventArgs e)
    {
      _activeStorage = cboStorages.SelectedItem as IImageStorage;
      ShowActiveStorageSettings();
    }

    private void OnClosing(object sender, FormClosingEventArgs e)
    {
      foreach (ISettingsControl holder in GetSettingsUIHolders())
      {
        holder.CancelClicked();
      }
    }

    private void OnStoragesTabPaint(object sender, PaintEventArgs e)
    {
      e.Graphics.FillRectangle(SystemBrushes.Control, 0, 0, Width, pnlSettings.Top);
      e.Graphics.DrawLine(SystemPens.ActiveBorder, 0, pnlSettings.Top - 1, tabStorage.Width, pnlSettings.Top - 1);
    }

    #endregion
  }
}